using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using NetProtocol.Enum;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public partial class MainCityModule : Singleton<MainCityModule>, IGameplaySceneArea
    {
        public GameplayAreaType areaType => GameplayAreaType.MainCity;
        public MainCityController mainController { get; private set; }
        public int curRegionCid => mainController.regionCtrl.cfgRegion.Id;
        public TNavigationController navigationCtrl => mainController.regionCtrl.navigationCtrl;
        public bool isInMainCity => mainController != null;
        public bool isSceneReady => isInMainCity && mainController.isSceneReady;

        private MainCityModule()
        {
        }

        public async UniTask OnEnter(object userData)
        {
            mainController = new MainCityController();
            EnterMainCityData data = userData as EnterMainCityData;
            int regionCid = data == null || data.regionCid == 0 ? MainCityConst.DefaultRegion : data.regionCid;
            await mainController.Enter(regionCid);
            if (data != null && data.portalMcid != 0)
            {
                TeleportInRegionByPortalMcid(data.portalMcid);
            }
        }

        public void OnLeave()
        {
            mainController.Dispose();
            mainController = null;
            BattleManager.Instance.Dispose();
        }

        public TViewEntity GetPlayerAvatarEntity()
        {
            if (!isSceneReady)
            {
                return null;
            }
            return mainController.regionCtrl.entityCtrl.playerAvatarEntity;
        }

        public TViewEntity GetEntityByMcid(int id)
        {
            if (!isSceneReady)
            {
                return null;
            }
            return mainController.regionCtrl.entityCtrl.GetEntityByMcid(id);
        }

        public TViewEntity GetEntityById(int id)
        {
            if (!isSceneReady)
            {
                return null;
            }
            return mainController.regionCtrl.entityCtrl.GetEntityById(id);
        }

        public void SearchEntities(List<TViewEntity> result, Func<TViewEntity, bool> searchFunc)
        {
            if (result == null || searchFunc == null)
            {
                LogGame.LogError("参数result和searchFunc均不能为空");
                return;
            }
            if (!isSceneReady)
            {
                return;
            }
            foreach (var entity in mainController.regionCtrl.entityCtrl.entities.Values)
            {
                if (searchFunc(entity))
                {
                    result.Add(entity);
                }
            }
        }

        public void GetEntitiesAround(List<TViewEntity> entities, float radius)
        {
            if (!isSceneReady)
            {
                return;
            }
            var playerPos = mainController.regionCtrl.entityCtrl.playerAvatarEntity.transform.position;
            var area = GameMathUtil.GetRectRangeV2(playerPos, radius);
            List<MainCityBaseEntity> mainCityEntities = ListPool<MainCityBaseEntity>.Get();
            mainController.regionCtrl.entityCtrl.QTQueryObjects(mainCityEntities, area);
            foreach (var e in mainCityEntities)
            {
                entities.Add(e);
            }

            ListPool<MainCityBaseEntity>.Put(mainCityEntities);
        }

        public bool IsPlayerMoving()
        {
            if (!isSceneReady)
            {
                return false;
            }
            return mainController.regionCtrl.gamepadCtrl.isMoving;
        }

        public TViewEntity GetTrackingEntity()
        {
            if (!isSceneReady)
            {
                return null;
            }
            var entityCtrl = mainController.regionCtrl.entityCtrl;
            var p = entityCtrl.playerAvatarEntity;
            if (p == null)
            {
                return null;
            }
            if (p.manualTrackingEntity == 0)
            {
                return null;
            }
            return GetEntityById(p.manualTrackingEntity);
        }

        public async UniTask MarkTrackingEntity(int entityId)
        {
            if (!isSceneReady)
            {
                return;
            }
            var entityCtrl = mainController.regionCtrl.entityCtrl;
            var p = entityCtrl.playerAvatarEntity;
            if (p == null)
            {
                LogGame.LogError("找不到玩家实体");
                return;
            }
            p.manualTrackingEntity = entityId;
            await GameScenePlayUtil.ShowEntityTrack();
        }

        public async UniTask TeleportToPortalByMcid(int regionCid, int portalMcid)
        {
            var regionCtrl = mainController.regionCtrl;
            if (regionCid == regionCtrl.cfgRegion.Id)
            {
                TeleportInRegionByPortalMcid(portalMcid);
                return;
            }
            else
            {
                await mainController.SwitchRegion(regionCid);
                TeleportInRegionByPortalMcid(portalMcid);
            }
        }

        private void TeleportInRegionByPortalMcid(int portalMcid)
        {
            var entity = GetEntityByMcid(portalMcid) as MainCityBaseEntity;
            if (entity == null)
            {
                LogGame.LogError($"找不到实体。mcid：{portalMcid}。");
                return;
            }
            TeleportInRegion(entity.id, Vector3.zero);
        }

        public async UniTask TeleportToRegion(int regionCid, int portalId)
        {
            if (!isSceneReady)
            {
                return;
            }
            var regionCtrl = mainController.regionCtrl;
            if (regionCid == regionCtrl.cfgRegion.Id)
            {
                TeleportInRegion(portalId, Vector3.zero);
                return;
            }
            else
            {
                await mainController.SwitchRegion(regionCid);
                TeleportInRegion(portalId, Vector3.zero);
            }
        }

        private void TeleportInRegion(int portalId, Vector3 offset)
        {
            var entityCtrl = mainController.regionCtrl.entityCtrl;
            var portalEntity = entityCtrl.GetEntityById(portalId);
            if (portalEntity == null)
            {
                LogGame.LogError($"找不到传送点实体。id：{portalId}");
                return;
            }
            entityCtrl.playerAvatarEntity.Teleport(portalEntity.unityPosOfData + offset);
        }

        public async UniTask<bool> SwitchPhasing(GameScenePhasing phasing, Vector3 mainPhasingPos = default)
        {
            if (!isSceneReady)
            {
                return false;
            }
            var viewRange = phasing == GameScenePhasing.Main ? MainCityConst.DefaultPlayerViewRadius : 0f;
            mainController.regionCtrl.entityCtrl.ChangePlayerViewRange(viewRange);
            var maxRefreshInterval = MainCityConst.PlayerViewRefreshInterval;
            await UniTask.Delay(maxRefreshInterval.SecToMillisec());
            MsgDispatcher.Broadcast(MsgEventType.SwitchPhasingSuccess, phasing);
            return true;
        }

        public void ChangeDisplayTime(int hour24)
        {
            if (!isSceneReady)
            {
                return;
            }
            mainController.regionCtrl.sceneCtrl.skybox?.SetTimeHour24(hour24);
        }

        public (bool, int) CheckCondition(int conditionCid, TViewEntity interactingEntity)
        {
            if (!isSceneReady)
            {
                return (false, 0);
            }
            if (interactingEntity != null && interactingEntity is not MainCityBaseEntity)
            {
                LogGame.LogError($"参数interactingEntity不是当前模块的类型（{nameof(MainCityBaseEntity)}）");
                return (false, 0);
            }

            (bool, int) result;
            var blackboard = ClassPool<ConditionBlackboard>.Get();
            {
                blackboard.enviroment = mainController.regionCtrl;
                blackboard.curPlayer = mainController.playerData;
                blackboard.curEntity = (IConditionPropFetcher)interactingEntity;
                result = ConditionModule.Instance.Check(conditionCid, blackboard);
            }
            ClassPool<ConditionBlackboard>.Put(blackboard);
            return result;
        }
    }
}